/*
 * Created on Nov 8, 2003
 */
package org.vectrics.recruiter.user;

import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.Session;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import org.vectrics.common.db.DataUtils;
import org.vectrics.common.db.JdbcUpdate;
import org.vectrics.common.util.DateSync;
import org.vectrics.common.util.DateUtil;
import org.vectrics.common.util.FileUtil;
import org.vectrics.company.CompanySelectCriteria;
import org.vectrics.domain.Domain;
import org.vectrics.hibernate.ThreadProperties;
import org.vectrics.hibernate.HibernateUtil;
import org.vectrics.hibernate.Filter;
import org.vectrics.hibernate.Selector;
import org.vectrics.provider.CoreServiceLocator;
import org.vectrics.recruiter.RecruitServiceLocator;
import org.vectrics.recruiter.config.RecruitConfig;
import org.vectrics.recruiter.document.CandidateDocument;
import org.vectrics.recruiter.document.CandidateDocumentCategory;
import org.vectrics.recruiter.document.CandidateDocumentIndexer;
import org.vectrics.recruiter.job.Job;
import org.vectrics.recruiter.job.JobApplication;
import org.vectrics.recruiter.job.JobCandidate;
import org.vectrics.recruiter.job.JobSearchCriteria;
import org.vectrics.recruiter.job.JobStatusType;
import org.vectrics.recruiter.user.resume.ResumeScanner;
import org.vectrics.recruiter.user.resume.email.EmailExtractor;
import org.vectrics.recruiter.user.resume.email.EmailedResumeAttachment;
import org.vectrics.recruiter.user.resume.email.EmailedResumeCriteria;
import org.vectrics.recruiter.user.resume.email.EmailedResumeInfo;
import org.vectrics.recruiter.user.resume.email.NameExtractor;
import org.vectrics.recruiter.user.resume.email.PhoneNumberExtractor;
import org.vectrics.recruiter.user.resume.email.PhoneNumberExtractorUS;
import org.vectrics.recruiter.user.resume.email.WordExtractor;
import org.vectrics.recruiter.user.resume.email.WordList;
import org.vectrics.user.Person;
import org.vectrics.user.PersonEncounterCriteria;
import org.vectrics.user.PersonEncounterDateComparator;
import org.vectrics.user.PersonEncounterStatusType;
import org.vectrics.user.PersonMatch;
import org.vectrics.user.PersonMatchSet;
import org.vectrics.user.PersonName;
import org.vectrics.user.PersonNameList;
import org.vectrics.user.PersonPersistMgr;
import org.vectrics.user.UserPrivilege;
import org.vectrics.user.PersonSearchCriteria;
import org.vectrics.DataException;
import org.vectrics.SystemException;


public class RecruitUserPersistMgr extends PersonPersistMgr implements RecruitUserProvider {
	private transient static Logger log = Logger.getLogger(RecruitUserPersistMgr.class);

	public RecruitUserPersistMgr() {
		super();
	}
	public int findInterviewCount(InterviewCriteria criteria) {
		InterviewSearcher searcher = RecruitServiceLocator.getInterviewSearcher();
		return(searcher.findInterviewCount(criteria));
	}
	
	/**
	 * find the list of interviews that match the criteria, return the subset of the list between the
	 * element indexes of startIndex and endIndex.
	 */
	public List findInterviews(InterviewCriteria criteria, int startIndex, int endIndex) {
		InterviewSearcher searcher = RecruitServiceLocator.getInterviewSearcher();
		return(searcher.findInterviews(criteria, startIndex, endIndex));
	}

	public CandidateDocumentCategory findCandidateDocumentCategory(String categoryCode) {
		return((CandidateDocumentCategory)ThreadProperties.getSession().load(CandidateDocumentCategory.class, categoryCode));
	}

	public Collection findCandidateActiveJobs(Person person) {
		Boolean active = new Boolean(true);
		return(findCandidateJobs(person, active));
	}

	public Collection findCandidateInactiveJobs(Person person) {
		Boolean active = new Boolean(false);
		return(findCandidateJobs(person, active));
	}

	public List findInterviewForJobCandidate(JobCandidate jobCandidate) {
		List resultList = new ArrayList();
		Collection candidateInterviews = this.findCandidateInterviews(jobCandidate.getCandidate());
		Iterator iter = candidateInterviews.iterator();
		while (iter.hasNext()) {
			Interview interview = (Interview)iter.next();
			if (interview.getJob() != null) {
				if (interview.getJob().getId().equals(jobCandidate.getJob().getId())) {
					resultList.add(interview);
				}
			}
		}
		return(resultList);
	}

	/**
	 * Return all Interview results that are possible for a particular status.
	 */
	public Collection findInterviewResultTypesForStatus(PersonEncounterStatusType statusType) {
		Filter filter = new Filter();
		filter.addFrom("InterviewResultType", "resultType");
		filter.addSelectField("resultType");
		filter.addParameterCondition("resultType.interviewStatusType.code", "=", statusType.getCode());
		return(filter.createQuery(ThreadProperties.getSession()).list());
	}
	
	/**
	 * Find all interviews for a candidate.
	 */
	public Collection findCandidateInterviews(CandidateInfo candidate) {
		if (candidate == null)
			throw new SystemException("Candidate was passed as NULL to method");
		Collection interviews = null;
		Session session = ThreadProperties.getSession();
		interviews = session.createQuery(
				"from Interview interview where (interview.person.id = ?) and" +
				" (interview.voided = 'F') order by interview.dateStart")
				.setLong(0, candidate.getPerson().getId().longValue())
				.list();
		return(interviews);
	}

	public void wipeResumeIndex(Domain domain) {
		String updateSql = "update user_resume set last_indx_dtm = null where active = 'T'";
		JdbcUpdate.execute(ThreadProperties.getSession(), updateSql);
		CandidateDocumentIndexer indexer = new CandidateDocumentIndexer(domain);
		indexer.wipeResumeIndex();
	}


	//NEED TO SAVE A FILE FOR TEMP FILE
	private void saveCandidateDocument(CandidateDocument document, String originalFileName) {
		if (document.getId() == null) {
			if (document.getSavedFileName() == null)
				throw new SystemException("Saved file name not set before calling this method");
			log.info("Document not saved yet" +
					"\r\n - Document:        " + document + 
					"\r\n - Saved file name: " + document.getSavedFileName()
					);
			if (document.getDomain() == null)
				throw new SystemException("CandidateDocument must have a Domain assigned before creation");
			if (document.getCategory() == null)
				throw new SystemException("CandidateDocument must have a category assigned before creation");
			if ((document.getDescription() != null) && (document.getDescription().length() > CandidateDocument.COLUMN_DESCRIPTION_LENGTH)) {
				String truncatedDescription = document.getDescription().substring(0, CandidateDocument.COLUMN_DESCRIPTION_LENGTH - 1);
				document.setDescription(truncatedDescription);
			}
			//document.setSavedFileName("temporary-name");
			document.setOriginalFileName(originalFileName);
			document.setDateCreated(DateSync.getCurrentTime());
			ThreadProperties.getSession().saveOrUpdate(document);
		} else {
			ThreadProperties.getSession().saveOrUpdate(document);
		}
	}

	/*
	 *  (non-Javadoc)
	 * @see org.vectrics.recruiter.user.RecruitUserProvider#createCandidateDocument(org.vectrics.recruiter.document.CandidateDocument, java.lang.String)
	 */
	public void createCandidateDocumentForUserTextEntered(CandidateDocument textDocument, String resumeText) {
		String documentPath = RecruitServiceLocator.getRecruitConfiguration()
			.getCandidateDocumentPath(textDocument.getDomain());
		
		String extension = "txt";
		log.info("Creating document: " + textDocument.toString());
			
		String fileName = textDocument.getId() + "." + extension;
		FileUtil.createDirectoryIfNotExist(documentPath);

		try {
			FileOutputStream file = new FileOutputStream(documentPath + "/" + fileName, true);
			
			for (int i = 0; i < resumeText.length(); i++) {
				int c = resumeText.charAt(i); 
				file.write(c);
			}
			file.close();
		} catch (Exception ex) {
			log.error("Exception writing content to file", ex);
			throw new SystemException("Exception writing content to file", ex);
		}
		textDocument.setSavedFileName(fileName);
		this.saveCandidateDocument(textDocument, "text");
	}

	
	public void createCandidateDocument(CandidateDocument textDocument, String originalFileName, 
			InputStream contentStream) {
		log.info("createCandidateDocument() called");
		if (originalFileName == null)
			throw new SystemException("originalFileName was passed as null to " +
					"createCandidateDocument() - must have value");
		Domain domain = textDocument.getDomain();
		String extension = FileUtil.findFileExtention(originalFileName);
		
		String fileName = "doc";
			
		this.saveCandidateDocument(textDocument, originalFileName);
		
		// Genero el path file name donde se va a guardar el archivo.
		String pathFileName = textDocument.getPerson().getFirstName()+ "_" + textDocument.getPerson().getLastName() + "_"
            + textDocument.getPerson().getId().toString() + "/" 
            + textDocument.getCategory();
		
        if (textDocument.getSavedFileName()==null){
			 fileName += textDocument.getId().toString() + "." + extension;			
		} else {
			 fileName = textDocument.getSavedFileName()+ textDocument.getId().toString() + "." + extension;
		}
		
		try {
			String documentPath = RecruitServiceLocator.getRecruitConfiguration()
				.getCandidateDocumentPath(domain);
            
			documentPath += "/" + pathFileName;
			
			FileUtil.createDirectoryIfNotExist(documentPath);
			FileUtil.saveInputStreamToFile(contentStream, documentPath + "/" + fileName);
		} catch (Exception ex) {
			log.error("Exception writing content to file", ex);
			throw new SystemException("Exception writing content to file", ex);
		}
		textDocument.setSavedFileName(pathFileName+ "/" +fileName);
		
		
		this.saveCandidateDocument(textDocument, originalFileName);
	}

	public void updateCandidateDocument(CandidateDocument document) {
		ThreadProperties.getSession().saveOrUpdate(document);
	}
	
	public Collection findCandidateJobs(Person person, Boolean active) {
		Collection jobs = null;
		Session session = ThreadProperties.getSession();
		Boolean voided = new Boolean(false);
		jobs = session.createQuery(
				"from JobCandidate jobCandidate where (jobCandidate.candidate.id = ?) " +
				"and (jobCandidate.job.active = ?) and (jobCandidate.job.voided = ?)")
				.setLong(0, person.getId().longValue())
				.setBoolean(1, active.booleanValue())
				.setBoolean(2, voided.booleanValue())
				.list();
		return(jobs);
	}

	/*
	 * Find jobs
	 */
	public List findJobsForJobAgent(JobAgent agent, int maxCount) {
		JobSearchCriteria criteria = new JobSearchCriteria();
		criteria.addStatusTypeCode(JobStatusType.STATUS_POSTED);
		criteria.setSearchWords(agent.getSearchPhrase());

		Calendar latestDate = Calendar.getInstance();
		latestDate.setTime(new Date());
		latestDate.add(Calendar.DATE, 1);

		Calendar earliestDate = Calendar.getInstance();
		earliestDate.setTime(new Date());
		earliestDate.add(Calendar.DATE, 0 - agent.getDaysBack().intValue());

		if (log.isDebugEnabled())
			log.debug("Date range: " + earliestDate.getTime() + "  to  " + latestDate);

		criteria.setEarliestPostDate(earliestDate.getTime());
		criteria.setLatestPostDate(latestDate.getTime());

		Iterator iter = agent.getJobFunctions().iterator();
		while (iter.hasNext()) {
			JobAgentFunction agentFunction = (JobAgentFunction)iter.next();
			criteria.addJobFunction(agentFunction.getJobFunction());
			
		}
		
		iter = agent.getLocations().iterator();
		while (iter.hasNext()) {
			JobAgentLocation agentLocation = (JobAgentLocation)iter.next();
			criteria.addLocation(agentLocation.getLocation());
		}
		criteria.addDomain(agent.getCandidateInfo().getPerson().getDomain());

		List jobs = RecruitServiceLocator.getJobProvider().findJobs(criteria, 0, maxCount);

		return(jobs);
	}


	/*
	 * Find all job search agents for the passed userId.
	 */
	public List findPersonJobAgents(Person person)  {
		List agents = null;
		Session session = ThreadProperties.getSession();
		try {
			agents = session.createQuery(
					"from JobAgent agent where (agent.candidateInfo.id = ?)")
					.setLong(0, person.getId().longValue())
					.list();
		} catch (Exception ex) {
			log.error("Exception doing query: ", ex);
		} finally {
		}
		return(agents);
	}

	/*
	 *
	 *
	 */
	public JobAgent findJobAgent(Long jobAgentId)  {
		if (jobAgentId == null)
			throw new SystemException("findJobAgent(jobAgentId) was passed a null id");
		JobAgent agent = null;
		Session session = ThreadProperties.getSession();
		agent = (JobAgent)session.load(JobAgent.class, jobAgentId);
		return(agent);
	}

	/*
	 * Find job agents that have expired and need to be invoked.
	 */
	public List findExpiredJobAgents(Domain domain, Date expirationTime, int maxCount) {
		List agentList = null;

		Session session = ThreadProperties.getSession();
		try {

			Filter filter = getFilterForExpiredJobAgents(domain, expirationTime);
			filter.addSelectField("agent");

			Query query = null;
			query = filter.createQuery(session);

			if (log.isDebugEnabled())
			    log.debug("Expired agents query: " + filter.getStatement());


			if (log.isDebugEnabled()) {
				log.debug("Expired agents query: " + query.getQueryString());
				log.debug("Expired agents date : " + expirationTime);
				log.debug("Statement = " + filter.getStatement());
			}

			query.setMaxResults(maxCount);
			query.setFirstResult(0);
			agentList = query.list();

			if (log.isDebugEnabled())
			    log.debug("agent count = " + agentList.size());
		}
		catch (Exception ex) {
			log.info("findExpiredJobAgents(): ", ex);
		}
		finally {
		}


		if (agentList == null)
		    agentList = new ArrayList();
		return(agentList);
	}



	private Filter getFilterForExpiredJobAgents(Domain domain, Date expiredTime) {
		log.debug("getFilterForCriteria()");
		Filter filter = new Filter();
		filter.setConjunction(Selector.CONJUNTION_AND);
		filter.addFrom("JobAgent", "agent");
		//filter.addOrderBy("agent.triggerDate");
		filter.addCondition("agent.active='T'");
		filter.addParameterCondition("agent.candidateInfo.person.domain.id", "=", domain.getId());
		filter.addParameterCondition("agent.triggerDate", "<", CoreServiceLocator
						.getDateFormat().getDateTimeFormatForSql().format(expiredTime));
		return(filter);
	}


/*
	public List findResumes(Long personId) {
		if (log.isDebugEnabled()) {
			log.debug("findResumes() - person Id = " + personId);
		}
		List resumes = null;
		Session session = null;
		try {
			session = hibernate.getThreadSession();
			resumes = session.createQuery(
					"from Resume as resume where (resume.person.id = ?)")
					.setLong(0, personId.longValue())
					.list();
		}
		catch (Exception ex) {
			log.error("Exception doing query: ", ex);
		}
		finally {
			hibernate.closeSessionOld(session);
		}
		return(resumes);
	}
*/
/*
	public Resume createResume(Person person)  {
		log.debug("createResume() - person id = " + person.getId());
		Resume resume = new Resume();
		resume.setPerson(person);

		Session session = null;
		session = hibernate.getThreadSession();
		session.save(resume);

		return(resume);
	}

	public Resume findResume(Long resumeId)  {
		Resume resume = null;
		Session session = null;
		try {
			session = hibernate.getThreadSession();
			resume = (Resume)session.load(Resume.class, resumeId);
		}
		catch (Exception he) {
			log.error("Hibernate exception finding resume");
		}
		finally {
			hibernate.closeSessionOld(session);
		}
		return(resume);
	}

	public void removeResume(Resume resume)  {
		Session session = null;
		if (resume != null) {
			log.debug("removing attachment files of this resume");
			if (resume.getFileAttached()) {
				String fileNameAndPath = resume.getFileName();
				try {
					if (fileNameAndPath.endsWith(".doc")) {
						WordDocumentReader reader = new WordDocumentReader();
						String text = reader.wordDocToString(fileNameAndPath);
						resume.setEntireResume("Orignal document deleted, below is the text: \r\n" + text);
					}

					File file = new File(fileNameAndPath);
					file.delete();
				} catch (Exception ex) {
					log.warn("Exception converting word resume to text, or deleting file");
				}
			}
			log.debug("Deleting resume");
			Logger.getLogger("org.hibernate").setLevel(Level.DEBUG);
			session = hibernate.getThreadSession();
			resume.setVoided(true);
			session.update(resume);
			session.flush();
			Logger.getLogger("org.hibernate").setLevel(Level.INFO);
			log.debug("Done deleting resume");
		}
	}

	public void updateResume(Resume resume)  {
		Session session = null;
		if (resume != null) {
			session = hibernate.getThreadSession();
			resume.setLastUpdate(DateSync.getCurrentTime());
			session.saveOrUpdate(resume);
		}
	}
*/

	public void updateJobAgentLocation(JobAgentLocation jobAgentLocation) {
		ThreadProperties.getSession().saveOrUpdate(jobAgentLocation);
	}
	
	
	/*
	 * Index Resume
	 */
	public void writeDocumentToScanIndex(CandidateDocument document) {
		CandidateDocumentIndexer indexer = null;
		try {
			indexer = new CandidateDocumentIndexer(document.getDomain());
			log.info("indexing document");
			indexer.indexDocument(document);
			// Update the resume object, we can't call updateResume() method because
			// it will change the 'lastUpdated' property and this will cause problems
			// because 'lastIndex' needs to be greater.
			Session session = ThreadProperties.getSession();
			session.saveOrUpdate(document);
			ThreadProperties.forcedCommit();
		} catch (Exception ex) {
			log.error("Exception indexing document, document.id: " + document.getId(), ex);
			ThreadProperties.rollbackTransaction();
			Session session = ThreadProperties.getSession();
			ThreadProperties.beginTransaction();
			document.setIndexError(true);
			document.setLastIndex(DateSync.getCurrentTime());
			session.saveOrUpdate(document);
			ThreadProperties.forcedCommit();
			log.info("Updated document object with error information");
		} finally {
			if (indexer != null) {
				indexer.close();
			}
		}
	}

	/*
	 * Update or create job agent.
	 */
	public void updateJobAgent(JobAgent jobAgent) {
		log.debug("updateJobAgent() called");
		Session session = ThreadProperties.getSession();
		if (jobAgent.getCandidateInfo() == null)
		    throw new SystemException("Attempted to save job agent without candidate assigned.");
		if (jobAgent.getCandidateInfo().getId() == null)
		    throw new SystemException("Attempted to save job agent without candidate saved.");
		if (jobAgent.getCandidateInfo().getPerson().getId() == null)
		    throw new SystemException("Attempted to save job agent with transient candidate.");

		if (jobAgent != null) {
		    session.saveOrUpdate(jobAgent);
		}
	}


	public Resume getLatestResume(CandidateInfo candidateInfo) {
		Resume resume = null;
		Collection allResumesForUser = candidateInfo.getResumes(); // if (findResumes (Resume)findResumes(userId);
		allResumesForUser = DataUtils.removeVoided(allResumesForUser);
		if (allResumesForUser.size() > 0) {
			Iterator iter = allResumesForUser.iterator();
			while (iter.hasNext()) {
				Resume curResume = (Resume)iter.next();
				if ((resume == null) || (resume.getLastUpdate().compareTo(
				        curResume.getLastUpdate()) < 0)) {
						resume = curResume;
				}
			}
		}
		return(resume);
	}

	public List findResumeIds(int maxDaysOld, Collection functionalAreas) {
		List resumeIds = new Vector();
		Date now = new Date();
		Date earliestDate = new Date(now.getTime() - (maxDaysOld * DateUtil.MILLIS_IN_A_DAY));
		Session session = ThreadProperties.getSession();
		try {
			Iterator iter = session
				.createQuery("select resume.id from Resume resume WHERE (resume.lastUpdate > ?) ")
				.setDate(0, earliestDate)
				.iterate();
			while (iter.hasNext()) {
				Long resumeId = (Long)iter.next();
				resumeIds.add(resumeId);
			}
		}
		catch (Exception ex) {
			log.error("Exception doing query: ", ex);
		}
		return(resumeIds);
	}


	public void removeJobAgents(CandidateInfo candidateInfo) {
		try {
			Session session = ThreadProperties.getSession();
			if (candidateInfo != null) {
				Iterator iter = candidateInfo.getJobAgents().iterator();
				while (iter.hasNext()) {
				    JobAgent agent = (JobAgent)iter.next();
				    agent.setVoided(true);
				    session.saveOrUpdate(agent);
				}
			}
		}
		catch (Exception he) {
			log.error("clearJobAgents() - hibernate exception", he);
			throw new DataException(he);
		}
	}

	/*
	 * Retrieve candidate info from database.
	 */
	public CandidateInfo findCandidateInfo(Person person)  {
		CandidateInfo candidateInfo = null;
		Session session = ThreadProperties.getSession();
	//	session.clear();
		Collection candidates = session.createQuery(
				"from CandidateInfo candidate where (candidate.person.id = ?)")
				.setLong(0, person.getId().longValue())
				.list();
	    if (candidates.size() > 0) {
	        candidateInfo = (CandidateInfo)candidates.iterator().next();
	    }
		return(candidateInfo);
	}

	public CandidateInfo findCandidateInfoById(Long id, boolean fetchJobAgents)  {
		CandidateInfo candidateInfo = null;
		Session session = ThreadProperties.getSession();
		session.evict(CandidateInfo.class);
		candidateInfo = (CandidateInfo)session.load(CandidateInfo.class, id);
		if (fetchJobAgents) {
		    candidateInfo.getJobAgents();
		}
		return(candidateInfo);
	}

	/*
	 *
	 * Save candidate information to database.
	 */
	public void updateCandidateInfo(CandidateInfo candidateInfo) {
		Session session = ThreadProperties.getSession();
		session.saveOrUpdate(candidateInfo);
	}


	public CandidateInfo createCandidateInfoIfNotExist(Person person)  {
		log.debug("getCreateResume()");
		CandidateInfo candidateInfo = findCandidateInfo(person);
		if (candidateInfo == null) {
			candidateInfo = new CandidateInfo();
			candidateInfo.setPerson(person);
		}
		return(candidateInfo);
	}



	public void setCandidateActive(Person user, boolean active)  {
		CandidateInfo candidateInfo = createCandidateInfoIfNotExist(user);
		candidateInfo.setVoided(active);
		try {
			Session session = ThreadProperties.getSession();
			session.update(candidateInfo);
		}
		catch (Exception he) {
			log.error("setCandidateActive() - exception", he);
			throw new DataException(he);
		}
	}

	public void setCandidateTerms(Person user, boolean lookingFullTime, boolean lookingPartTime, boolean lookingContract, boolean lookingPermanent)  {
		CandidateInfo candidateInfo = createCandidateInfoIfNotExist(user);
		candidateInfo.setLookingContract(lookingContract);
		candidateInfo.setLookingFullTime(lookingFullTime);
		candidateInfo.setLookingPartTime(lookingPartTime);
		candidateInfo.setLookingPermanent(lookingPermanent);
		Session session = ThreadProperties.getSession();
		session.update(candidateInfo);
	}

	public void setCandidateTravel(Person user, int travelPercent)  {
		CandidateInfo candidateInfo = createCandidateInfoIfNotExist(user);
		candidateInfo.setTravelPercent(new Integer(travelPercent));
		try {
			Session session = ThreadProperties.getSession();
			session.update(candidateInfo);
		} catch (Exception he) {
			log.error("setCandidateActive() - exception", he);
			throw new DataException(he);
		}
	}

	public Interview findInterviewById(Long interviewId) {
		Interview interview = null;
		try {
			Session session = ThreadProperties.getSession();

			interview = (Interview)session.load(Interview.class, interviewId);
		} catch (Exception he) {
			log.error("Hibernate exception", he);
			throw new DataException("Hibernate exception", he);
		}
		return(interview);
	}

	public Interview createInterview(JobCandidate jobCandidate, Person leadPerson)  {
		Person person = jobCandidate.getCandidate().getPerson();
		if (person == null) {
			throw new SystemException("Need to set person for job candidate before creating interview");
		}
		if (person.getId() == null) {
			throw new SystemException("Need to save person before creating interview");
		}
		if (jobCandidate.getId() == null) {
			throw new SystemException("Need to save job candidate before creating interview");
		}
		Job job = jobCandidate.getJob();
		log.debug("createInterview() - called");
		Interview savedInterview = new Interview();
		try {
			savedInterview.setDateStart(new Date());
			savedInterview.setDomain(jobCandidate.getJob().getDomain());
			savedInterview.setDateEnd(new Date(savedInterview.getDateStart().getTime() + DateUtil.MILLIS_IN_A_HOUR));
			savedInterview.setPerson(person);
			PersonEncounterStatusType statusType = CoreServiceLocator.getPersonService().findPersonEncounterStatusType(PersonEncounterStatusType.STATUS_SCHEDULED);
			if (statusType == null) {
				throw new SystemException("Illegal null for status type");
			}
			savedInterview.setLeadPerson(leadPerson);
			savedInterview.setStatusType(statusType);
			savedInterview.setJob(job);

			Session session = ThreadProperties.getSession();
			session.save(savedInterview);
		}
		catch (Exception he) {
			log.error("createInterview() - Exception", he);
			throw new DataException("createInterview() - Exception", he);
		}
		return(savedInterview);
	}


	/*
	 *  Update the database with the passed interview.
	 */
	public void updateInterview(Interview interview)  {
		log.debug("saveUserResumeText() - called");
		Session session = ThreadProperties.getSession();
		session.saveOrUpdate(interview);
	}


	public void removeInterview(Interview interview)  {
		log.debug("saveUserResumeText() - called");

		Session session = ThreadProperties.getSession();
		session.delete(interview);
	}


	public List findScheduledInterviews(Date startDate, Date endDate) {
		log.debug("findScheduledInterviews() - finding interviews between passed dates");
		List interviews = null;
		Session session = ThreadProperties.getSession();
		try {
			interviews = session.createQuery(
					"from Interview as interview where interview.dateStart >= ? AND interview.dateStart <= ? order by interview.dateStart")
					.setDate(0, startDate)
					.setDate(0, endDate)
					.list();
			if (log.isDebugEnabled()) {
				log.debug("findScheduledInterviews() - startDate = " + startDate);
				log.debug("findScheduledInterviews() - endDate = " + endDate);
				log.debug("findScheduledInterviews() - after query, count = " + interviews.size());
			}
		}
		catch (Exception ex) {
			log.debug("findScheduledInterviews() - Exception doing query: ", ex);
			interviews = new ArrayList();
		}
		return(interviews);
	}

	public Collection getEmployments(Person user)  {
		Collection employments = new Vector();
		// TODO
		return(employments);
	}

	public UserEmployment findEmployment(Person user, String empId)  {
		UserEmployment userEmployment = null;
		//TODO
		return(userEmployment);
	}

	public UserEmployment createEmployment(Person user) {
		UserEmployment employment = null;
		// TODO
		return(employment);
	}

	public void removeEmployment(Person person) {
		// TODO
	}

	public Collection getEducations(Person user) {
		Collection educations = new Vector();
		//TODO
		return(educations);
	}


	public UserEducation findEducation(Person user) {
		UserEducation education = null;
		// TODO
		return(education);
	}

	public UserEducation createEducation(Person user) {
		UserEducation education = null;
		return(education);
	}

	public void removeEducation(Person user, String employmentId) {
		// TODO
	}


	public JobApplication findJobApplication(Job job, Person person) {
		JobApplication application = null;

		return(application);
	}


	public JobApplication applyToJob(Job job, Person person)  {
		JobApplication application = null;
		Session session = ThreadProperties.getSession();
		try {
			application = findJobApplication(job, person);
			if (application == null)
			    application = new JobApplication();
		}
		catch (Exception he) {
			log.error("Hibernate exception finding resume");
		} 
		return(application);
	}


	/*
	 * Return resume scan batches count for a person.
	 */
    public int findResumeScanBatchesCount(ResumeScanBatchCriteria criteria) {
        int count = 0;

		Session session = ThreadProperties.getSession();
		try {
			Filter filter = getFilterForResumeScanBatches(criteria, false);
			filter.addSelectField("count(distinct b.id)");


			Query query = null;
			query = filter.createQuery(session);

			if (log.isDebugEnabled()) {
				log.debug("findResumeScanBatchesCount() - Statement = " + filter.getStatement());
			}

			Object obj = query.iterate().next();
			Integer countInt = (Integer)obj;
			count = countInt.intValue();

		}
		catch (Exception he) {
			log.error("Hibernate exception finding resume");
		}
		return(count);
	}


	/*
	 * Return resume scan batches for a person.
	 */
	public List findResumeScanBatches(ResumeScanBatchCriteria criteria, int start, int end) {
	    List elements = new ArrayList();
		Session session = ThreadProperties.getSession();
		try {
			Filter filter = getFilterForResumeScanBatches(criteria, false);
			filter.addSelectField("b");

			Query query = null;
			query = filter.createQuery(session);

			if (log.isDebugEnabled()) {
				log.debug("Statement = " + filter.getStatement());
			}
			if ((end >= 0) && (start >= 0)) {
				query.setMaxResults(1 + end - start);
				query.setFirstResult(start);
			}
			elements.addAll(query.list());
		}
		catch (Exception he) {
			log.error("Hibernate exception finding resume");
		}

	    return(elements);
	}


	public Filter getFilterForResumeScanBatches(ResumeScanBatchCriteria criteria, boolean ordered) {
		log.debug("getFilterForCriteria()");
		Filter filter = new Filter();
		filter.setConjunction(Selector.CONJUNTION_AND);
		filter.addFrom("ResumeScanBatch", "b");
		if (ordered)
		    filter.addOrderBy("b.runDate desc");


		Selector sharedSelector = filter.getSelector().addChildSelector(Selector.CONJUNTION_OR);
		sharedSelector.addCondition("b.shared='T'");
		sharedSelector.addParameterCondition("b.runPerson.id", "=", criteria.getRunPerson().getId());

		if ((criteria.getDomains() != null) && (criteria.getDomains().size() > 0)) {
			Selector domainSelector = filter.getSelector().addChildSelector(Selector.CONJUNTION_OR);
			Iterator iter = criteria.getDomains().iterator();
			while (iter.hasNext()) {
				Domain domain = (Domain)iter.next();
				domainSelector.addParameterCondition("b.domain.id", "=", domain.getId());
			}
		}
		
		if (criteria.getJob() != null) {
			filter.addFrom("ResumeScanBatchJob", "resumeScanBatchJob");
			filter.addParameterCondition("resumeScanBatchJob.job.id", "=", criteria.getJob().getId());
			filter.addCondition("b.id=resumeScanBatchJob.resumeScanBatch.id");
		}
		
		
		
		return(filter);
	}



    public int findResumeScanResultsCount(Long batchNumber) {
        int count = 0;

		Session session = ThreadProperties.getSession();
		try {
			Filter filter = getFilterForResumeScanResults(batchNumber, false);
			filter.addSelectField("count(distinct r.id)");

			Query query = null;
			query = filter.createQuery(session);

			if (log.isDebugEnabled()) {
				log.debug("Statement = " + filter.getStatement());
			}

			Object obj = query.iterate().next();
			Integer countInt = (Integer)obj;
			count = countInt.intValue();
		}
		catch (Exception he) {
			log.error("Hibernate exception finding resume");
		}
		return(count);
	}


	/*
	 * Return resume scan results for batch represented by the batchNumber parameter.
	 */
	public List findResumeScanResults(Long batchNumber, int start, int end) {
	    List elements = new ArrayList();
		Session session = ThreadProperties.getSession();
		try {
			Filter filter = getFilterForResumeScanResults(batchNumber, false);
			filter.addSelectField("r");

			Query query = null;
			query = filter.createQuery(session);

			if (log.isDebugEnabled()) {
				log.debug("Statement = " + filter.getStatement());
			}
			if ((end >= 0) && (start >= 0)) {
				query.setMaxResults(1 + end - start);
				query.setFirstResult(start);
			}
			elements.addAll(query.list());

		}
		catch (Exception he) {
			log.error("Hibernate exception finding resume");
		}
	    return(elements);
	}

	public Filter getFilterForResumeScanResults(Long batchId, boolean ordered) {
		log.debug("getFilterForCriteria()");
		Filter filter = new Filter();
		filter.setConjunction(Selector.CONJUNTION_AND);
		filter.addFrom("ResumeScanResult", "r");
		if (ordered)
		    filter.addOrderBy("r.score");

		filter.getSelector().addParameterCondition("r.batch.id", "=", batchId);
		return(filter);
	}

	public void removeAllCriteria(ResumeScanBatch batch)  {
		log.debug("saveUserResumeText() - called");

		Session session = ThreadProperties.getSession();
		Iterator iter = batch.getCriteriaList().iterator();
		while (iter.hasNext()) {
			ResumeScanCriteria criteria = (ResumeScanCriteria)iter.next();
			session.delete(criteria);
		}
		batch.getCriteriaList().clear();
	}

	public void removeResumeScanBatch(ResumeScanBatch batch)  {
		log.debug("removeResumeScanBatch() - called");
		this.clearResumeScanResults(batch);
		Session session = ThreadProperties.getSession();

		log.info("**************** Delete batch: " + batch.getId());

		session.delete(batch);

	}

	public void updateResumeScanBatch(ResumeScanBatch batch)  {
		log.debug("saveUserResumeText() - called");
		Session session = ThreadProperties.getSession();
		batch.setCriteriaList(batch.getCriteriaList());
		session.saveOrUpdate(batch);
	}


	public ResumeScanBatch findResumeScanBatch(Long batchNumber)  {
		log.debug("saveUserResumeText() - called");
		ResumeScanBatch batch = null;
		Session session = ThreadProperties.getSession();
		batch = (ResumeScanBatch)session.load(ResumeScanBatch.class, batchNumber);
		return(batch);
	}

	public void updateResumeScanResult(ResumeScanResult result)  {
		log.debug("updateResumeScanResult() - called");
		Session session = ThreadProperties.getSession();
		try {
			session.saveOrUpdate(result);
		}
		catch (Exception he) {
			log.error("updateResumeScanResult() - Exception", he);
			throw new DataException("updateResumeScanResult() - Exception", he);
		} 
	}


	public void performResumeScan(ResumeScanBatch batch) {
		synchronized(batch) {
			batch.setRunDate(DateSync.getCurrentTime());
			batch.setRunCompletionDate(null);
			batch.setStatus(ResumeScanBatch.STATUS_RUNNING);
			this.updateResumeScanBatch(batch);

			HashSet functionalAreas = new HashSet();
			int maxDaysOld = batch.getMaxResumeAge().intValue();
			this.clearResumeScanResults(batch);
			this.createResumeScanResults(batch, maxDaysOld, functionalAreas);

			batch.setStatus(ResumeScanBatch.STATUS_FINISHED);
			batch.setRunCompletionDate(DateSync.getCurrentTime());
			this.updateResumeScanBatch(batch);
		}
	}


	public void clearResumeScanResults(ResumeScanBatch batch) {
		Session session = ThreadProperties.getSession();
		Iterator iter = session.createQuery("from ResumeScanResult r where r.batch.id = ?")
			.setLong(0, batch.getId().longValue())
			.iterate();
		while (iter.hasNext()) {
			Object obj = iter.next();
			session.delete(obj);
		}
	}

	private void addKeyword(Set keywordWeights, String word, int weight) {
		if ((word != null) && (word.trim().length() > 0)) {
			KeywordWeight keywordWeight = new KeywordWeight();
			keywordWeight.setKeyword(word);
			keywordWeight.setWeight(weight);
			keywordWeights.add(keywordWeight);
		}
	}

	/*
	 *
	 */
	private void createResumeScanResults(ResumeScanBatch batch, int maxDaysOld, Collection functionalAreas) {
		ResumeScanner scanner = new ResumeScanner(batch);
		try {
			scanner.scan(batch);
		} catch (FileNotFoundException fnfe) {
			log.warn("File not found error scanning resumes - index may not be built yet.");
		}
		//scanner.
	}



	public JobApplication findJobApplication(Long applicationId) {
	    JobApplication application = null;
		Session session = ThreadProperties.getSession();
		try {
			application = (JobApplication)session.load(JobApplication.class, applicationId);
		}
		catch (Exception he) {
			log.error("Hibernate exception finding job application");
		}
	    return(application);
	}


	public void updateJobApplication(JobApplication jobApplication) {
		Session session = ThreadProperties.getSession();
		try {
			session.saveOrUpdate(jobApplication);
		}
		catch (Exception he) {
			log.error("Hibernate exception updating job app", he);
		}
	}

	public void updateEmailedResumeAttachment(EmailedResumeAttachment attachment) {
		if (attachment.getEmailedResumeInfo().getId() == null)
			throw new SystemException("Owner of attachment (EmailedResumeInfo) has not been saved.");
		Session session = ThreadProperties.getSession();
		session.saveOrUpdate(attachment);
	}

	public void updateEmailedResume(EmailedResumeInfo emailedResumeInfo) {
		Session session = ThreadProperties.getSession();
		session.saveOrUpdate(emailedResumeInfo);
	}

	public Filter getFilterForEmailedResumeCriteria(EmailedResumeCriteria criteria) {
		Filter filter = new Filter();
		filter.addFrom("EmailedResumeInfo", "info");
		if (criteria.getStatusList().size() > 0) {
			Selector statusSelector = filter.getSelector().addChildSelector(Selector.CONJUNTION_OR);
			Iterator iter = criteria.getStatusList().iterator();
			while (iter.hasNext()) {
				String statusCode = (String)iter.next();
				statusSelector.addParameterCondition("info.statusCode", "=", statusCode);
			}
		}
		filter.addOrderBy("info.dateSent desc");
		return(filter);
	}

	public int findEmailedResumesCount(EmailedResumeCriteria criteria) {
		Filter filter = this.getFilterForEmailedResumeCriteria(criteria);
		int count = HibernateUtil.findElementCount(filter, "info");
		return(count);
	}

	public List findEmailedResumes(EmailedResumeCriteria criteria, int startIndex, int endIndex) {
		List elements = null;
		Filter filter = this.getFilterForEmailedResumeCriteria(criteria);
		filter.addSelectField("info");

		elements = HibernateUtil.findElements(filter, startIndex, endIndex);

		if (log.isDebugEnabled()) {
			log.debug("Statement = " + filter.getStatement());
		}
		return(elements);
	}


	private Filter getFilterForResumeExpire(Domain domain) {
		log.debug("getFilterForCriteria()");
		Filter filter = new Filter();
		filter.setConjunction(Selector.CONJUNTION_AND);
		filter.addSelectField("r");
		filter.addFrom("Resume", "r");
	    Calendar maxLastChangeDate = Calendar.getInstance();
	    maxLastChangeDate.setTime(DateSync.getCurrentTime());
	    long daysForResumeToExpire = RecruitConfig.getRecruitInstance().getResumeExpireDays(domain);
	    maxLastChangeDate.add(Calendar.DATE, 0 - (int)daysForResumeToExpire);

		filter.getSelector().addParameterCondition("r.lastUpdate", "<", maxLastChangeDate.getTime());
		filter.getSelector().addParameterCondition("r.voided", false);
		filter.addOrderBy("r.lastUpdate");
		return(filter);
	}


	public Collection findResumesThatHaveExpired(Domain domain, int startIndex, int endIndex) {
		Filter filter = this.getFilterForResumeExpire(domain);
		List elements = HibernateUtil.findElementsFromFilter(filter, startIndex, endIndex);
		return(elements);
	}


	private Filter getFilterForDocumentsNeedingIndexing(Domain domain) {
		log.debug("getFilterForCriteria()");
		Filter filter = new Filter();
		filter.setConjunction(Selector.CONJUNTION_AND);
		filter.addFrom("CandidateDocument", "d");
		filter.addSelectField("d");
		filter.addParameterCondition("d.domain.id", "=", domain.getId());
		Selector subSel = filter.getSelector().addChildSelector(Selector.CONJUNTION_OR);
		subSel.addCondition("d.lastIndex < d.lastUpdate");
		subSel.addCondition("d.lastIndex is null");
		filter.getSelector().addCondition("d.voided='F'");
		filter.addOrderBy("d.lastUpdate desc");
		if (log.isDebugEnabled())
			log.debug("Index select statement: " + filter.getStatement());
		return(filter);
	}


	public Collection findDocumentsForIndexing(Domain domain, int startIndex, int endIndex) {
		Filter filter = this.getFilterForDocumentsNeedingIndexing(domain);
		
		List elements = HibernateUtil.findElementsFromFilter(filter, startIndex, endIndex);
		return(elements);
	}


	public Filter getFilterForActiveCandidates() {
		log.debug("getFilterForActiveCandidates()");
		Filter filter = new Filter();
		filter.setConjunction(Selector.CONJUNTION_AND);
		filter.addFrom("CandidateInfo", "candidate");
	    filter.addOrderBy("candidate..score");

		filter.getSelector().addParameterCondition("candidate.active", true);
		filter.getSelector().addParameterCondition("candidate.voided", false);
		return(filter);
	}

	public List findActiveCandidates(Domain domain, int startIndex, int endIndex) {
		Filter filter = this.getFilterForDocumentsNeedingIndexing(domain);
		List elements = HibernateUtil.findElementsFromFilter(filter, startIndex, endIndex);

		return(elements);
	}

	public EmailedResumeInfo findEmailedResume(Long id) {
		return (EmailedResumeInfo)ThreadProperties.getSession().load(EmailedResumeInfo.class, id);
	}

	public EmailedResumeAttachment findEmailedResumeAttachment(Long id) {
		return((EmailedResumeAttachment)ThreadProperties.getSession().load(EmailedResumeAttachment.class, id));
	}
	
	
	/*
	 * Find candidates that might be the same person that email the resume.  This
	 * is determined by searching the contents of the email for possible names,
	 * email addresses and phone numbers.
	 */
	public PersonMatchSet findPossibleCandidates(EmailedResumeInfo info) {
		log.debug("findPossibleCandidates() - starting - method to parse emailed resume and email body to find currently stored people");
		if (info == null)
			throw new SystemException("EmailedResumeInfo was passed to this function with value of NULL");
		if (info.getDomain() == null)
			throw new SystemException("EmailedResumeInfo.domain was passed to this function with value of NULL");

		Set phoneNumbers = new HashSet();
		PersonNameList nameList = new PersonNameList();
		Set emails = new HashSet();
		WordExtractor wordExtractor = RecruitServiceLocator.getWordExtractor();

		Iterator iter = info.getAttachments().iterator();
		while (iter.hasNext()) {
			EmailedResumeAttachment attachment = (EmailedResumeAttachment)iter.next();
			String content =  info.getFromEmailName() + " " + info.getFromEmailAddress() 
					+ " " + attachment.getDocument().getTextContent();

			log.debug("Finding words in attachment content");
			WordList wordList = wordExtractor.getWordList(content);
			
			try {
				log.debug("Extracting names from found content words");
				NameExtractor nameExtractor = new NameExtractor();
				nameList.addAll(nameExtractor.findNamesInText(wordList));

				log.debug("Extracting emails from found content words");
				EmailExtractor emailExtractor = new EmailExtractor();
				emails.addAll(emailExtractor.findEmailInText(wordList));
				
				log.debug("Extracting phone number from found content words");
				PhoneNumberExtractor phoneExtractor = new PhoneNumberExtractorUS();
				phoneNumbers.addAll(phoneExtractor.findPhoneNumbersInText(wordList));
			} catch (Exception ex) {
				log.error("Exception extracting data from word list: " + wordList, ex);
				throw new SystemException("Exception extracting data from word list: " + wordList, ex);
			}
		}
		log.debug("Find possible candidates from extracted data");
		
		PersonMatchSet matchSet = this.findPossibleCandidates(info.getDomain(), nameList, emails, phoneNumbers);
		matchSet.setPhoneNumbers(phoneNumbers);
		matchSet.setNames(nameList);
		matchSet.setEmailAddresses(emails);
		log.debug("findPossibleCandidates() - finished");
		
		return matchSet;
	}

	public PersonMatchSet findPossibleCandidates(Domain domain, PersonNameList nameList, Set emails, Set phoneNumbers) {
		if (domain == null)
			throw new SystemException("Domain was passed to this function with value of NULL");

		PersonMatchSet personMatches = new PersonMatchSet();

		Iterator nameIter = nameList.iterator();
		while (nameIter.hasNext()) {
			PersonName personName = (PersonName)nameIter.next();
			PersonSearchCriteria criteria = CoreServiceLocator.createPersonSearchCriteria();
			
			criteria.addDomain(domain);

			criteria.setLastName(personName.getLastName());
			criteria.setFirstName(personName.getFirstName());
			List personsWithName = CoreServiceLocator.getPersonService().findPersons(criteria, 0, 10);
			Iterator iter = personsWithName.iterator();
			while (iter.hasNext()) {
				Person person = (Person)iter.next();
				PersonMatch personMatch = new PersonMatch();
				personMatch.setPerson(person);
				personMatch.setScore(new Long(90));
				personMatches.add(personMatch);
			}
		}

		Iterator phoneIter = phoneNumbers.iterator();
		while (phoneIter.hasNext()) {
			String phoneNumber = (String)phoneIter.next();
			PersonSearchCriteria criteria = CoreServiceLocator.createPersonSearchCriteria();
			criteria.setAnyPhone(phoneNumber);
			criteria.addDomain(domain);
			List personsWithPhone = CoreServiceLocator.getPersonService().findPersons(criteria, 0, 10);
			Iterator iter = personsWithPhone.iterator();
			while (iter.hasNext()) {
				Person person = (Person)iter.next();
				PersonMatch personMatch = new PersonMatch();
				personMatch.setPerson(person);
				personMatch.setScore(new Long(90));
				personMatches.add(personMatch);
			}
		}

		Iterator emailIter = emails.iterator();
		while (emailIter.hasNext()) {
			String email = (String)emailIter.next();
			PersonSearchCriteria criteria = CoreServiceLocator.createPersonSearchCriteria();
			criteria.setEmail(email);
			criteria.addDomain(domain);
			List personsWithEmail = CoreServiceLocator.getPersonService().findPersons(criteria, 0, 10);
			Iterator iter = personsWithEmail.iterator();
			while (iter.hasNext()) {
				Person person = (Person)iter.next();
				PersonMatch personMatch = new PersonMatch();
				personMatch.setPerson(person);
				personMatch.setScore(new Long(90));
				personMatches.add(personMatch);
			}
		}
		return(personMatches);
	}


	public Resume findResume(Long id) {
		return (Resume)ThreadProperties.getSession().load(Resume.class, id);
	}

	public void updateResume(Resume resume) {
		if (resume.getVoided()) {
			log.debug("If resume is voided, then remove from index");
			if ((resume.getDocument() != null) && (resume.getDocument().getLastIndex() != null)) {
				CandidateDocumentIndexer indexer = new CandidateDocumentIndexer(resume.getDomain());
				indexer.removeDocumentFromIndex(resume.getDocument());
			}
		}
		ThreadProperties.getSession().saveOrUpdate(resume);
	}

	public List findAllCandidateDocumentCategories() {
		Filter filter = new Filter();
		filter.addFrom("CandidateDocumentCategory", "category");
		filter.addSelectField("category");
		Query query = filter.createQuery(ThreadProperties.getSession());
		return(query.list());
	}

	
	public Set findJobAdminCompaniesForAuthPerson(Person authPerson) {
		Set companies = new HashSet();
		
		if (authPerson.hasDomainOrGlobalRole("job.view", null) == true) {
			
			log.debug("User is a global administrator, can view jobs of all companies");
			
		} else {
			Iterator userPrivilegesIter = authPerson.getPrivileges().iterator();
			while (userPrivilegesIter.hasNext()) {
				UserPrivilege userPrivilege = (UserPrivilege)userPrivilegesIter.next();
				if (userPrivilege.getPrivilegeType().getCode().equals(RecruitUserConstants.ROLE_JOB_VIEW)) {
					Domain domain = userPrivilege.getDomain();
					if (domain != null) {
						CompanySelectCriteria criteria = new CompanySelectCriteria();
						criteria.addDomain(domain);
						Collection companiesOfDomain = CoreServiceLocator.getCompanyService().findCompanies(criteria, 0, 1000);
						
						companies.addAll(companiesOfDomain);
					}
				}
					
			}
		}
		return(companies);
	}

	/*
	 *  (non-Javadoc)
	 * @see org.vectrics.recruiter.user.RecruitUserProvider#saveResumeToFile(org.vectrics.recruiter.user.CandidateInfo, org.vectrics.recruiter.user.Resume, java.lang.String, java.io.InputStream)
	 */
	public void saveResumeToFile(CandidateInfo candidate, Resume resume, String originalFileName, InputStream contentStream) {
		log.info("saveResumeToFile() -creating document");
		CandidateDocument candidateDocument = new CandidateDocument();
		candidateDocument.setDomain(resume.getDomain());
		candidateDocument.setCategory(CandidateDocumentCategory.CATEGORY_RESUME);
		candidateDocument.setPerson(candidate.getPerson());
		candidateDocument.setOriginalFileName(originalFileName);
		candidateDocument.setSavedFileName(resume.getName());
		candidateDocument.setName(resume.getName());
		log.info("saveResumeToFile() -creating document");
		this.createCandidateDocument(candidateDocument, originalFileName, contentStream);
		resume.setDocument(candidateDocument);
		ThreadProperties.getSession().saveOrUpdate(resume);
	}

	
	public void saveUploadedResumeToFile(CandidateInfo candidate, Resume resume, String resumeText) {
		CandidateDocument candidateDocument = new CandidateDocument();
		candidateDocument.setDomain(resume.getDomain());
		candidateDocument.setCategory(CandidateDocumentCategory.CATEGORY_RESUME);
		candidateDocument.setPerson(candidate.getPerson());
		candidateDocument.setOriginalFileName(null);
		this.createCandidateDocumentForUserTextEntered(candidateDocument, resumeText);
		resume.setDocument(candidateDocument);
		ThreadProperties.getSession().saveOrUpdate(resume);
	}
	
	
	public CandidateDocument findCandidateDocument(Long documentId) {
		CandidateDocument document = (CandidateDocument)ThreadProperties.getSession().load(CandidateDocument.class, documentId);
		return(document);
	}

	public int findCandidateDocumentCount(Person person) {
		int count = 0;
		Filter filter = new Filter();
		filter.addFrom("CandidateDocument", "candidateDocument");
		filter.addSelectField("count(distinct candidateDocument)");
		filter.addParameterCondition("candidateDocument.person.id", "=", person.getId());
		Query query = filter.createQuery(ThreadProperties.getSession());
		Iterator results = query.iterate();

		if (results == null) {
			throw new DataException("Method does not define logic for criteria");
		} else {
			while ( results.hasNext() ) {
				Object row = (Object)results.next();
				Long countInteger = (Long)row;
				count = countInteger.intValue();
			}
		}
		return(count);
	}
	
	
	public List findCandidateDocuments(Person person, int startIndex, int endIndex) {
		Filter filter = new Filter();
		filter.addFrom("CandidateDocument", "candidateDocument");
		filter.addSelectField("candidateDocument");
		filter.addParameterCondition("candidateDocument.person.id", "=", person.getId());
		filter.addOrderBy("candidateDocument.dateCreated");
		Query query = filter.createQuery(ThreadProperties.getSession());

		query.setCacheable(false);

		if ((endIndex >= 0) && (startIndex >= 0)) {
			query.setMaxResults(1 + endIndex - startIndex);
			query.setFirstResult(startIndex);
		}
		List results = query.list();
		return(results);
	}

	
	public ResumeScanBatchJob findResumeScanBatchJob(Job job) {
		ResumeScanBatchJob resumeScanBatchJob = null;
		
		Filter filter = new Filter();
		filter.addFrom("ResumeScanBatchJob", "resumeScanBatchJob");
		filter.addSelectField("resumeScanBatchJob");
		filter.addParameterCondition("resumeScanBatchJob.job.id", "=", job.getId());
		
		Query query = filter.createQuery(ThreadProperties.getSession());
		Iterator iter = query.iterate();
		if (iter.hasNext()) {
			resumeScanBatchJob = (ResumeScanBatchJob)iter.next();
		}
		return(resumeScanBatchJob);
	}
	

	public ResumeScanBatchJob createResumeScanBatchJob(Job job, ResumeScanBatch resumeScanBatch) {
		ResumeScanBatchJob resumeScanBatchJob = this.findResumeScanBatchJob(job);
		if (resumeScanBatchJob != null)
			this.removeResumeScanBatchJob(resumeScanBatchJob);
		
		resumeScanBatchJob = new ResumeScanBatchJob();
		resumeScanBatchJob.setJob(job);
		resumeScanBatchJob.setResumeScanBatch(resumeScanBatch);
		resumeScanBatchJob.setCreateDate(DateSync.getCurrentTime());
		ThreadProperties.getSession().save(resumeScanBatchJob);
		return(resumeScanBatchJob);
	}
	
	
	public void removeResumeScanBatchJob(ResumeScanBatchJob resumeScanBatchJob) {
		ThreadProperties.getSession().delete(resumeScanBatchJob);
	}
	
	public Resume findResume(CandidateDocument document) {
		Resume resume = null;
		Filter filter = new Filter();
		filter.addFrom("Resume", "resume");
		filter.addSelectField("resume");
		filter.addParameterCondition("resume.document.id", "=", document.getId());
		
		Query query = filter.createQuery(ThreadProperties.getSession());
		Iterator iter = query.iterate();
		if (iter.hasNext()) {
			resume = (Resume)iter.next();
		}
		return(resume);
	}
	
	
	public Collection findAllEncounters(Person person) {
		Collection encounters = new HashSet();
		
		CandidateInfo candidate = this.findCandidateInfo(person);
		encounters.addAll(this.findCandidateDocuments(person, 0, 10000));
		encounters.addAll(this.findCandidateInterviews(candidate));
		//encounters.addAll(CoreServiceLocator.getPersonService().findPersonCommunications(person));
		
		TreeSet sortedEncounters = new TreeSet(new PersonEncounterDateComparator());
		sortedEncounters.addAll(encounters);
		
		return(sortedEncounters);
	}
	
	/**
	 * Find Interview result type for code.
	 */
	public InterviewResultType findInterviewResultType(String resultTypeCode) {
		InterviewResultType resultType = (InterviewResultType)ThreadProperties.getSession().load(InterviewResultType.class, resultTypeCode);
		return(resultType);
	}
	
	/**
	 * Overrides super 
	 */
	public List findPersonEncounters(PersonEncounterCriteria criteria) {
		List encounters = super.findPersonEncounters(criteria);
		InterviewCriteria interviewCriteria = new InterviewCriteria();
		interviewCriteria.setPerson(criteria.getPerson());
		interviewCriteria.setStartDate(criteria.getStartDate());
		interviewCriteria.setEndDate(criteria.getEndDate());
		encounters.addAll(this.findInterviews(interviewCriteria, 0, 1000));
		return(encounters);
	}
	
	/**
	 * 
	 * @see RecruitUserProvider#saveFile(Person, String, String, InputStream)
	 */
	public void saveFile(Person person, String category,
			String originalFileName, InputStream contentStream, String name) {
		log.info("saveFile() -creating document");
		CandidateDocument candidateDocument = new CandidateDocument();
		candidateDocument.setDomain(ThreadProperties.getDomain());
		candidateDocument.setCategory(category);
		candidateDocument.setPerson(person);
		candidateDocument.setOriginalFileName(originalFileName);
		candidateDocument.setSavedFileName(name);
		candidateDocument.setName(name);
		log.info("saveResumeToFile() -creating document");
		this.createCandidateDocument(candidateDocument, originalFileName, contentStream);
	}
	
	/**
	 * @throws IOException 
	 * @see RecruitUserProvider#removeDocument(CandidateDocument)
	 */
	public void removeDocument(CandidateDocument document) throws IOException {
		String fileAndPath = RecruitConfig.getRecruitInstance().getCandidateDocumentPath(document.getDomain())
	                               + "/"  + document.getSavedFileName();
		
		File fichero = new File(fileAndPath);
		if (!fichero.delete()) {
			throw new IOException("No se puede borrar el archivo");
		}
		Session session = ThreadProperties.getSession();
		session.delete(document);
		
	}
	
	/**
	 * 	 * @see RecruitUserProvider#removeResume(Resume)
	 */
	public void removeResume(Resume resume) {
		Session session = ThreadProperties.getSession();
		session.delete(resume);		
	}
	
}
